﻿using System;
using System.Threading;
using System.Collections.Generic;

using SBPweb.Communication.Shared.Library;
using SBPweb.Communication.Shared.Library.Contacts;
using SBPweb.Communication.Shared.Library.Commands;
using SBPweb.Communication.Shared.Library.Conversations;

using SBPweb.Communication.Client.Library.Xmpp.Contacts;
using SBPweb.Communication.Client.Library.Xmpp.Commands;

using Matrix.Xmpp.Disco;

namespace SBPweb.Communication.Client.Library.Xmpp.Conversations
{

    partial class ConversationManager : ConversationManagerBase
    {

        #region Private fields

        #endregion

        #region Methods

        public void FindPublicConferences()
        {
            GetPublicConferencesCommand findCmd = new GetPublicConferencesCommand("conference." + connections.client.Hostname);
            messenger.Commands.SendCommand(findCmd);
            if (FindPublicConferencesRequested != null)
            {
                FindPublicConferencesRequested(this, EventArgs.Empty);
            }
        }

        #region Event handlers

        #region Life cycle

        protected override void OnInitialize()
        {
            connections.Connected += new EventHandler(OnConnected);
            connections.client.OnMessage += new EventHandler<Matrix.Xmpp.Client.MessageEventArgs>(OnClientMessageReceive);
            messenger.Commands.RegisterCommandHandler<GetPublicConferencesCommand>(new EventHandler<CommandBaseEventArgs<GetPublicConferencesCommand>>(OnFindConferencesCommandReceived));
        }

        protected override void OnTerminate()
        {
            messenger.Commands.UnregisterCommandHandler<GetPublicConferencesCommand>(new EventHandler<CommandBaseEventArgs<GetPublicConferencesCommand>>(OnFindConferencesCommandReceived));
            connections.client.OnMessage -= new EventHandler<Matrix.Xmpp.Client.MessageEventArgs>(OnClientMessageReceive);
            connections.Connected -= new EventHandler(OnConnected);
        }

        private void OnConnected(object sender, EventArgs e)
        {
            //WTF?
            Thread.Sleep(500);
            if (Configuration.GetPublicConferencesWhenConnected)
            {
                FindPublicConferences();
            }
        }

        #endregion

        #region Conversations

        public override void OpenConference(string conferenceName)
        {
            OpenConference(new Contact(conferenceName + "@conference." + connections.client.Hostname));
        }

        public override void OpenConference(IContact conferenceId)
        {
            CreateConference(conferenceId, new List<IContact>(new IContact[] { LocalContact }));
        }

        public override void OpenConference(string conferenceName, List<IContact> members)
        {
            OpenConference(new Contact(conferenceName + "@conference." + connections.client.Hostname), members);
        }

        internal void OnClientMessageReceive(object sender, Matrix.Xmpp.Client.MessageEventArgs e)
        {
            IContact id;
            Conversation conv = null;

            switch (e.Message.Type)
            {
                default:
                    break;
                case Matrix.Xmpp.MessageType.chat:
                    {
                        id = new Contact(e.Message.From);
                        if (conversations.ContainsKey(id))
                        {
                            conv = conversations[id] as Conversation;
                        }
                        else
                        {
                            conv = CreateConversation(new Contact(e.Message.From), LocalContact);
                        }
                    }
                    break;
                case Matrix.Xmpp.MessageType.groupchat:
                    {
                        id = new Contact(e.Message.From);
                        if (conversations.ContainsKey(id))
                        {
                            conv = conversations[id] as Conversation;
                        }
                        else
                        {
                            throw new NotImplementedException();
                            //conv = CreateConference(id, 
                        }
                        e.Message.To = new Matrix.Jid(conv.Receipient.Id);
                        e.Message.From = new Matrix.Jid(string.Format("{0}@{1}", e.Message.From.Resource, e.Message.From.Server.Replace("conference.", "")));
                    }
                    break;
            }

            if (conv != null)
            {
                Message m = new Message(e.Message);
                m.isOwn = m.From.Equals(LocalContact);
                conv.ReceiveMessage(m);
            }
        }

        internal void OnClientMessageSend(object sender, MessageBaseEventArgs e)
        {
            Conversation conv = sender as Conversation;

            Message msg = e.Message as Message;

            if (!conversations.ContainsValue(conv))
            {
                conv = CreateConversation(LocalContact, e.Message.To);
            }

            if (conv != null)
            {
                connections.client.Send(msg.message);
                if (!conv.IsConference)
                {
                    conv.ReceiveMessage(msg);
                }
            }
        }

        #endregion

        #region Conferences

        private void OnFindConferencesCommandReceived(object sender, CommandBaseEventArgs<GetPublicConferencesCommand> e)
        {
            if (PublicConferences == null)
            {
                PublicConferences = new List<IContact>();
            }
            else
            {
                PublicConferences.Clear();
            }
            foreach (Item dI in e.Command.ConferenceItems)
            {
                PublicConferences.Add(new Contact(dI.Jid.Bare, dI.Name));
            }
            if (FindPublicConferencesReceived != null)
            {
                FindPublicConferencesReceived(this, EventArgs.Empty);
            }
        }

        #endregion

        #endregion

        #endregion

    }

}